# Modeling
import xgboost as xgb
class XgbModel(object):
    def __init__(self, train_x, train_y, val_x, val_y):
        self.train_x = train_x
        self.train_y = train_y
        self.val_x = val_x
        self.val_y = val_y

    def train_model(self):
        DEBUG = False
        clf = xgb.XGBRegressor(
            device='cpu',
            enable_categorical=True,  # 自动推导表列内的数据类型
            objective='reg:absoluteerror',
            n_estimators=2 if DEBUG else 1500,  # 树的数量
            early_stopping_rounds=100  # 这个100指的是？ -> 连续100轮没有改善则会停止训练
        )

        clf.fit(X=self.train_x,
                y=self.train_y,
                eval_set=[(self.train_x, self.train_y), (self.val_x, self.val_y)],  # TODO: 这里为何把训练集又喂入
                verbose=True  # False #True
                )

        print(
            f'Early stopping on best iteration #{clf.best_iteration} with MAE error on validation set of {clf.best_score:.2f}')
        return clf
    def train_details(self,clf):
        ## 要先拿到训练结果
        import matplotlib.pyplot as plt
        import pandas as pd
        # Plot RMSE
        results = clf.evals_result()
        train_mae, val_mae = results["validation_0"]["mae"], results["validation_1"]["mae"]
        x_values = range(0, len(train_mae))
        fig, ax = plt.subplots(figsize=(8, 4))
        ax.plot(x_values, train_mae, label="Train MAE")
        ax.plot(x_values, val_mae, label="Validation MAE")
        ax.legend()
        plt.ylabel("MAE Loss")
        plt.title("XGBoost MAE Loss")
        plt.show()

        TOP = 20
        importance_data = pd.DataFrame({'name': clf.feature_names_in_, 'importance': clf.feature_importances_})
        importance_data = importance_data.sort_values(by='importance', ascending=False)

        import seaborn as sns
        fig, ax = plt.subplots(figsize=(8, 4))
        sns.barplot(data=importance_data[:TOP],
                    x='importance',
                    y='name'
                    )
        patches = ax.patches
        count = 0
        for patch in patches:
            height = patch.get_height()
            width = patch.get_width()
            perc = 100 * importance_data['importance'].iloc[count]  # 100*width/len(importance_data)
            ax.text(width, patch.get_y() + height / 2, f'{perc:.1f}%')
            count += 1

        plt.title(f'The top {TOP} features sorted by importance')
        plt.show()



